package cn.iocoder.yudao.module.trade.order.convert;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.business.basic.pojo.vo.UserSimpleVO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
import cn.iocoder.yudao.framework.region.RegionUtils;
import cn.iocoder.yudao.framework.region.enums.RegionDataSet;
import cn.iocoder.yudao.module.api.member.address.dto.MemberAddressRespDTO;
import cn.iocoder.yudao.module.api.member.user.dto.MemberUserSimpleRespDTO;
import cn.iocoder.yudao.module.api.product.evaluation.dto.ProductEvaluationCreateReqDTO;
import cn.iocoder.yudao.module.api.product.sku.dto.ProductSkuUpdateStockOrSalesCountReqDTO;
import cn.iocoder.yudao.module.api.promotion.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.api.trade.DictTypeConstants;
import cn.iocoder.yudao.module.api.trade.aftersale.enums.AfterSaleStatusEnum;
import cn.iocoder.yudao.module.api.trade.delivery.dto.ExpressTrackRespDTO;
import cn.iocoder.yudao.module.api.trade.order.dto.TradeOrderItemRespDTO;
import cn.iocoder.yudao.module.api.trade.order.dto.TradeOrderRespDTO;
import cn.iocoder.yudao.module.api.trade.order.vo.AppTradeOrderPageVO;
import cn.iocoder.yudao.module.trade.cart.dal.dataobject.CartDO;
import cn.iocoder.yudao.module.trade.delivery.dal.dataobject.DeliveryExpressDO;
import cn.iocoder.yudao.module.trade.framework.TradeOrderProperties;
import cn.iocoder.yudao.module.trade.order.bo.TradePriceCalculateReqBO;
import cn.iocoder.yudao.module.trade.order.bo.TradePriceCalculateRespBO;
import cn.iocoder.yudao.module.trade.order.dal.dataobject.TradeOrderDO;
import cn.iocoder.yudao.module.trade.order.dal.dataobject.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.order.dal.dataobject.TradeOrderLogDO;
import cn.iocoder.yudao.module.trade.order.vo.*;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
import static cn.iocoder.yudao.module.api.pay.ConfigConstants.PAY_TIMEOUT_MINUTES;

@Mapper
public interface TradeOrderConvert {

    TradeOrderConvert INSTANCE = Mappers.getMapper(TradeOrderConvert.class);

    @SuppressWarnings("UnmappedTargetProperties")
    @Mappings({
            @Mapping(source = "createReqVO.couponId", target = "couponId"),
            @Mapping(source = "createReqVO.grouponPackageId", target = "grouponPackageId"),
            @Mapping(target = "remark", ignore = true),
            @Mapping(source = "createReqVO.remark", target = "userRemark"),
            @Mapping(source = "calculateRespBO.price.totalPrice", target = "totalPrice"),
            @Mapping(source = "calculateRespBO.price.totalCostPrice", target = "settlementPrice"),
            @Mapping(source = "calculateRespBO.price.payPrice", target = "payPrice"),
            @Mapping(source = "calculateRespBO.price.discountPrice", target = "discountPrice"),
            @Mapping(source = "calculateRespBO.price.deliveryPrice", target = "deliveryPrice"),
            @Mapping(source = "calculateRespBO.price.couponPrice", target = "couponPrice"),
            @Mapping(source = "calculateRespBO.price.vipPrice", target = "vipPrice"),
            @Mapping(source = "calculateRespBO.deductPoint", target = "deductPoint"),
            @Mapping(source = "calculateRespBO.price.pointPrice", target = "pointPrice"),
            @Mapping(source = "calculateRespBO.givePoint", target = "givePoint"),
            @Mapping(source = "calculateRespBO.deductCryptocurrency", target = "deductCryptocurrency"),
            @Mapping(source = "calculateRespBO.price.cryptocurrencyPrice", target = "cryptocurrencyPrice"),
            @Mapping(source = "calculateRespBO.giveCryptocurrency", target = "giveCryptocurrency"),
            @Mapping(source = "calculateRespBO.giveBonus", target = "giveBonus"),
            @Mapping(source = "calculateRespBO.dinePeoples", target = "dinePeoples"),
    })
    TradeOrderDO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradePriceCalculateRespBO calculateRespBO);

    @SuppressWarnings("UnmappedTargetProperties")
    @Mappings({
            @Mapping(target = "price", source = "skuPrice"),
            @Mapping(target = "settlementPrice", source = "skuCostPrice"),
            @Mapping(target = "supplyName", source = "supplyName"),
            @Mapping(target = "supplyRelatedSkuId", source = "supplyRelatedSkuId"),
    })
    TradeOrderItemDO convert(TradePriceCalculateRespBO.OrderItem item);

    @SuppressWarnings("UnmappedTargetProperties")
    @Mapping(source = "orderItem.skuPrice", target = "price")
    @Mapping(source = "orderItem.skuCostPrice", target = "costPrice")
    @Mapping(source = "orderItem.skuVipPrice", target = "vipPrice")
    @Mapping(source = "orderItem.skuWholesaleForRetailPrice", target = "wholesaleForRetailPrice")
    AppTradeOrderSettlementItemRespVO orderItemToItem(TradePriceCalculateRespBO.OrderItem orderItem);

    TradeOrderRespDTO convert(TradeOrderDO orderDO);

    default List<TradeOrderItemDO> convertList(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) {
        return CollectionUtils.convertList(calculateRespBO.getItems(), item -> {
            TradeOrderItemDO orderItem = convert(item);
            orderItem.setShopId(tradeOrderDO.getShopId());
            orderItem.setOrderId(tradeOrderDO.getId());
            orderItem.setUserId(tradeOrderDO.getUserId());
            orderItem.setAfterSaleStatus(AfterSaleStatusEnum.NONE.getStatus());
            orderItem.setCommentStatus(false);
            return orderItem;
        });
    }

    List<TradeOrderItemRespDTO> convertList(List<TradeOrderItemDO> list);

    default ProductSkuUpdateStockOrSalesCountReqDTO convert(List<TradeOrderItemDO> list) {
        List<ProductSkuUpdateStockOrSalesCountReqDTO.Item> items = CollectionUtils.convertList(list, item -> {
            ProductSkuUpdateStockOrSalesCountReqDTO.Item xx = new ProductSkuUpdateStockOrSalesCountReqDTO.Item();
            xx.setId(item.getSkuId());
            xx.setIncCount(item.getCount());
            return xx;
        });
        return new ProductSkuUpdateStockOrSalesCountReqDTO(items);
    }

    default ProductSkuUpdateStockOrSalesCountReqDTO convertNegative(List<TradeOrderItemDO> list) {
        List<ProductSkuUpdateStockOrSalesCountReqDTO.Item> items = CollectionUtils.convertList(list, item -> {
            ProductSkuUpdateStockOrSalesCountReqDTO.Item xx = new ProductSkuUpdateStockOrSalesCountReqDTO.Item();
            xx.setId(item.getSkuId());
            xx.setIncCount(-1 * item.getCount());
            return xx;
        });
        return new ProductSkuUpdateStockOrSalesCountReqDTO(items);
    }

    default PageResult<TradeOrderPageItemRespVO> convertPage(PageResult<TradeOrderDO> pageResult,
                                                             List<TradeOrderItemDO> orderItems,
                                                             Map<Long, UserSimpleVO> memberUserMap) {
        Map<Long, List<TradeOrderItemDO>> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId);
        // 转化 List
        List<TradeOrderPageItemRespVO> orderVOs = CollectionUtils.convertList(pageResult.getList(), order -> {
            List<TradeOrderItemDO> xOrderItems = orderItemMap.get(order.getId());
            TradeOrderPageItemRespVO orderVO = convert(order, xOrderItems);
            // 处理收货地址
            orderVO.setReceiverAreaName(RegionUtils.formatRegionName(RegionDataSet.ONLY_LATEST, order.getReceiverAreaId(), ""));
            // 增加用户信息
            orderVO.setUser(convertUser(memberUserMap.get(orderVO.getUserId())));
            // 增加推广人信息
            orderVO.setBrokerageUser(convertUser(memberUserMap.get(orderVO.getBrokerageUserId())));
            return orderVO;
        });
        return new PageResult<>(orderVOs, pageResult.getTotal());
    }

    MemberUserSimpleRespDTO convertUser(UserSimpleVO memberUserRespDTO);

    TradeOrderPageItemRespVO convert(TradeOrderDO order, List<TradeOrderItemDO> items);

    default TradeOrderDetailRespVO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
                                           List<TradeOrderLogDO> orderLogs,
                                           UserSimpleVO user, UserSimpleVO brokerageUser) {
        TradeOrderDetailRespVO orderVO = convert2(order, orderItems);
        // 处理收货地址
        orderVO.setReceiverAreaName(RegionUtils.formatRegionName(RegionDataSet.ONLY_LATEST, order.getReceiverAreaId(), ""));
        // 处理用户信息
        orderVO.setUser(convert(user));
        orderVO.setBrokerageUser(convert(brokerageUser));
        // 处理日志
        orderVO.setLogs(convertList03(orderLogs));
        return orderVO;
    }

    List<TradeOrderDetailRespVO.OrderLog> convertList03(List<TradeOrderLogDO> orderLogs);

    TradeOrderDetailRespVO convert2(TradeOrderDO order, List<TradeOrderItemDO> items);

    MemberUserSimpleRespDTO convert(UserSimpleVO bean);

    default PageResult<AppTradeOrderPageVO> convertPage02(PageResult<TradeOrderDO> pageResult,
                                                          List<TradeOrderItemDO> orderItems) {
        Map<Long, List<TradeOrderItemDO>> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId);
        // 转化 List
        List<AppTradeOrderPageVO> orderVOs = CollectionUtils.convertList(pageResult.getList(), order -> {
            List<TradeOrderItemDO> xOrderItems = orderItemMap.getOrDefault(order.getId(), new ArrayList<>());
            AppTradeOrderPageVO pageVO = convert02(order, xOrderItems);
            if (CollUtil.isNotEmpty(xOrderItems)) {
                pageVO.setAfterSaleStatus(xOrderItems.get(0).getAfterSaleStatus());
            }
            return pageVO;
        });
        return new PageResult<>(orderVOs, pageResult.getTotal());
    }

    AppTradeOrderPageVO convert02(TradeOrderDO order, List<TradeOrderItemDO> items);

    default AppTradeOrderDetailRespVO convert02(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradeOrderProperties tradeOrderProperties, DeliveryExpressDO express) {
        AppTradeOrderDetailRespVO orderVO = convert3(order, orderItems);
        orderVO.setPayExpireTime(order.getCreateTime().plusMinutes(PAY_TIMEOUT_MINUTES));
        if (order.getPayTime() != null) {
            orderVO.setReceiveExpireTime(order.getPayTime().plusDays(tradeOrderProperties.getReceiveExpireTime().toDays()));
        }
        if (order.getFinishTime() != null) {
            orderVO.setCommentExpireTime(order.getFinishTime().plusDays(tradeOrderProperties.getCommentExpireTime().toDays()));
        }
        if (StrUtil.isNotEmpty(order.getPayChannelCode())) {
            orderVO.setPayChannelName(DictFrameworkUtils.parseDictDataLabel(DictTypeConstants.CHANNEL_CODE, order.getPayChannelCode()));
        }
        // 处理收货地址
        orderVO.setReceiverAreaName(RegionUtils.formatRegionName(RegionDataSet.ONLY_LATEST, order.getReceiverAreaId(), ""));
        if (express != null) {
            orderVO.setLogisticsId(express.getId());
            orderVO.setLogisticsName(express.getName());
        }
        return orderVO;
    }

    AppTradeOrderDetailRespVO convert3(TradeOrderDO order, List<TradeOrderItemDO> items);

    TradeOrderItemRespDTO convert03(TradeOrderItemDO bean);

    @Mappings({
            @Mapping(target = "orderId", source = "tradeOrderItemDO.orderId"),
            @Mapping(target = "orderItemId", source = "tradeOrderItemDO.id"),
            @Mapping(target = "scores", source = "createReqVO.scores"),
            @Mapping(target = "descriptionScores", source = "createReqVO.descriptionScores"),
            @Mapping(target = "benefitScores", source = "createReqVO.benefitScores"),
            @Mapping(target = "content", source = "createReqVO.content"),
            @Mapping(target = "picUrls", source = "createReqVO.picUrls"),
            @Mapping(target = "anonymous", source = "createReqVO.anonymous"),
    })
    ProductEvaluationCreateReqDTO convert04(AppTradeOrderItemEvaluationCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItemDO);

    @Mappings({
            @Mapping(target = "orderId", source = "orderDO.id"),
            @Mapping(target = "orderItemId", ignore = true),
            @Mapping(target = "scores", source = "createReqVO.scores"),
            @Mapping(target = "descriptionScores", source = "createReqVO.descriptionScores"),
            @Mapping(target = "benefitScores", source = "createReqVO.benefitScores"),
            @Mapping(target = "content", source = "createReqVO.content"),
            @Mapping(target = "picUrls", source = "createReqVO.picUrls"),
            @Mapping(target = "anonymous", source = "createReqVO.anonymous"),
    })
    ProductEvaluationCreateReqDTO convert05(AppTradeOrderEvaluationCreateReqVO createReqVO, TradeOrderDO orderDO);

    TradePriceCalculateReqBO convert(AppTradeOrderSettlementReqVO settlementReqVO);

    default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO,
                                             List<CartDO> cartList) {
        TradePriceCalculateReqBO reqBO = convert0(userId, settlementReqVO);
        // 产品项的构建
        Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId);
        for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) {
            // 情况〇：item 为空，如“{"items":[{},{"cartId":"1917112932689485826"}]}”
            if (item == null || (item.getSkuId() == null && item.getCartId() == null)) {
                continue;
            }
            // 情况一：skuId + count
            TradePriceCalculateReqBO.Item newItem = new TradePriceCalculateReqBO.Item();
            if (item.getCartId() == null) {
                newItem.setSkuId(item.getSkuId());
                newItem.setCount(item.getCount());
                newItem.setSelected(true);
                reqBO.getItems().add(newItem); // true 的原因，下单一定选中
                continue;
            }
            // 情况二：cartId
            CartDO cart = cartMap.get(item.getCartId());
            if (cart == null) {
                continue;
            }
            newItem.setSkuId(cart.getSkuId());
            newItem.setCount(cart.getCount());
            newItem.setCartId(item.getCartId());
            newItem.setSelected(true); // true 的原因，下单一定选中
            reqBO.getItems().add(newItem);
        }
        return reqBO;
    }

    private TradePriceCalculateReqBO convert0(Long userId, AppTradeOrderSettlementReqVO settlementReqVO) {
        TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO();
        reqBO.setUserId(userId);
        reqBO.setItems(new ArrayList<>(settlementReqVO.getItems().size()));
        reqBO.setCouponId(settlementReqVO.getCouponId());
        reqBO.setUseVipPrice(Boolean.TRUE.equals(settlementReqVO.getUseVipPrice()));
        reqBO.setUseWholesalePrice(Boolean.TRUE.equals(settlementReqVO.getUseWholesalePrice()));
        reqBO.setUsePointDeduction(Boolean.TRUE.equals(settlementReqVO.getUsePointDeduction()));
        reqBO.setUseCryptocurrencyDeduction(Boolean.TRUE.equals(settlementReqVO.getUseCryptocurrencyDeduction()));
        reqBO.setUseFirstOrderDiscount(Boolean.TRUE.equals(settlementReqVO.getUseFirstOrderDiscount()));
        // 物流信息
        reqBO.setDeliveryType(settlementReqVO.getDeliveryType());
        reqBO.setAddressId(settlementReqVO.getAddressId());
        reqBO.setPickUpStoreId(settlementReqVO.getPickUpStoreId());
        // 各种活动
        reqBO.setSeckillActivityId(settlementReqVO.getSeckillActivityId());
        reqBO.setBargainRecordId(settlementReqVO.getBargainRecordId());
        reqBO.setCombinationActivityId(settlementReqVO.getCombinationActivityId());
        reqBO.setCombinationHeadId(settlementReqVO.getCombinationHeadId());
        reqBO.setPointActivityId(settlementReqVO.getPointActivityId());
        reqBO.setGrouponPackageId(settlementReqVO.getGrouponPackageId());
        // 点餐信息
        reqBO.setDineDeskId(settlementReqVO.getDineDeskId());
        reqBO.setDinePeoples(settlementReqVO.getDinePeoples());
        return reqBO;
    }

    default AppTradeOrderSettlementRespVO convert(TradePriceCalculateRespBO calculate, MemberAddressRespDTO address) {
        if (address != null) {
            RegionUtils.autoAssignCounty(RegionDataSet.ONLY_LATEST, address.getCountyCode(), address);
        }
        return convert0(calculate, address);
    }

    @Mapping(target = "shop", ignore = true)
    AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, MemberAddressRespDTO address);

    List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);

    @SuppressWarnings("UnmappedTargetProperties")
    TradeOrderDO convert(TradeOrderUpdateAddressReqVO reqVO);

    @SuppressWarnings("UnmappedTargetProperties")
    TradeOrderDO convert(TradeOrderUpdatePriceReqVO reqVO);

    @SuppressWarnings("UnmappedTargetProperties")
    TradeOrderDO convert(TradeOrderRemarkReqVO reqVO);

    List<TradeOrderRespDTO> convertList04(List<TradeOrderDO> list);

    @Mappings({
            @Mapping(target = "activityId", source = "order.combinationActivityId"),
            @Mapping(target = "spuId", source = "item.spuId"),
            @Mapping(target = "skuId", source = "item.skuId"),
            @Mapping(target = "count", source = "item.count"),
            @Mapping(target = "orderId", source = "order.id"),
            @Mapping(target = "userId", source = "order.userId"),
            @Mapping(target = "headId", source = "order.combinationHeadId"),
            @Mapping(target = "combinationPrice", source = "item.payPrice"),
    })
    CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO item);

}
